package com.mj.haier.calc.web.rest;

import com.mj.haier.calc.domain.ItfOutcomeStatmentBean;
import com.mj.haier.calc.domain.ItfOutcomeStatmentDetailBean;
import com.mj.haier.calc.repository.AzFinSettleBillRepository;
import com.mj.haier.calc.repository.AzFinSettleCarsteamRepository;
import com.mj.haier.calc.repository.ItfOutcomeStatmentBeanRepository;
import com.mj.haier.calc.repository.ItfOutcomeStatmentDetailBeanRepository;
import com.mj.haier.calc.repository.search.ItfOutcomeStatmentBeanSearchRepository;
import com.mj.haier.calc.web.rest.errors.BadRequestAlertException;
import com.mj.haier.calc.web.rest.util.HeaderUtil;
import com.mj.haier.calc.web.rest.util.PaginationUtil;
import io.github.jhipster.web.util.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.*;

import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;

/**
 * REST controller for managing ItfOutcomeStatmentBean.
 */
@RestController
@RequestMapping("/api/azStatement")
public class ItfOutcomeStatmentBeanResource {

    private final Logger log = LoggerFactory.getLogger(ItfOutcomeStatmentBeanResource.class);

    private static final String ENTITY_NAME = "microCalcItfOutcomeStatmentBean";

    private final ItfOutcomeStatmentBeanRepository itfOutcomeStatmentBeanRepository;

    private final ItfOutcomeStatmentBeanSearchRepository itfOutcomeStatmentBeanSearchRepository;

    @Autowired
    private AzFinSettleCarsteamRepository azFinSettleCarsteamRepository;

    @Autowired
    private AzFinSettleBillRepository azFinSettleBillRepository;
    @Autowired
    private ItfOutcomeStatmentDetailBeanRepository itfOutcomeStatmentDetailBeanRepository;

    @Resource(name = "taskExecutor")
    private TaskExecutor taskExecutor;

    public ItfOutcomeStatmentBeanResource(ItfOutcomeStatmentBeanRepository itfOutcomeStatmentBeanRepository, ItfOutcomeStatmentBeanSearchRepository itfOutcomeStatmentBeanSearchRepository) {
        this.itfOutcomeStatmentBeanRepository = itfOutcomeStatmentBeanRepository;
        this.itfOutcomeStatmentBeanSearchRepository = itfOutcomeStatmentBeanSearchRepository;
    }

    /**
     * POST  /itf-outcome-statment-beans : Create a new itfOutcomeStatmentBean.
     *
     * @param itfOutcomeStatmentBean the itfOutcomeStatmentBean to create
     * @return the ResponseEntity with status 201 (Created) and with body the new itfOutcomeStatmentBean, or with status 400 (Bad Request) if the itfOutcomeStatmentBean has already an ID
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PostMapping("/itf-outcome-statment-beans")
    public ResponseEntity<ItfOutcomeStatmentBean> createItfOutcomeStatmentBean(@Valid @RequestBody ItfOutcomeStatmentBean itfOutcomeStatmentBean) throws URISyntaxException {
        log.debug("REST request to save ItfOutcomeStatmentBean : {}", itfOutcomeStatmentBean);
//        if (itfOutcomeStatmentBean.getBillNo() != null) {
//            throw new BadRequestAlertException("A new itfOutcomeStatmentBean cannot already have an ID", ENTITY_NAME, "idexists");
//        }
        ItfOutcomeStatmentBean result = itfOutcomeStatmentBeanRepository.save(itfOutcomeStatmentBean);
        itfOutcomeStatmentBeanSearchRepository.save(result);
        return ResponseEntity.created(new URI("/api/itf-outcome-statment-beans/" + result.getBillNo()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getBillNo().toString()))
            .body(result);
    }

    /**
     * PUT  /itf-outcome-statment-beans : Updates an existing itfOutcomeStatmentBean.
     *
     * @param itfOutcomeStatmentBean the itfOutcomeStatmentBean to update
     * @return the ResponseEntity with status 200 (OK) and with body the updated itfOutcomeStatmentBean,
     * or with status 400 (Bad Request) if the itfOutcomeStatmentBean is not valid,
     * or with status 500 (Internal Server Error) if the itfOutcomeStatmentBean couldn't be updated
     * @throws URISyntaxException if the Location URI syntax is incorrect
     */
    @PutMapping("/itf-outcome-statment-beans")
    public ResponseEntity<ItfOutcomeStatmentBean> updateItfOutcomeStatmentBean(@Valid @RequestBody ItfOutcomeStatmentBean itfOutcomeStatmentBean) throws URISyntaxException {
        log.debug("REST request to update ItfOutcomeStatmentBean : {}", itfOutcomeStatmentBean);
        if (itfOutcomeStatmentBean.getBillNo() == null) {
            throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
        }
        ItfOutcomeStatmentBean result = itfOutcomeStatmentBeanRepository.save(itfOutcomeStatmentBean);
        itfOutcomeStatmentBeanSearchRepository.save(result);
        return ResponseEntity.ok()
            .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, itfOutcomeStatmentBean.getBillNo().toString()))
            .body(result);
    }

    /**
     * GET  /itf-outcome-statment-beans : get all the itfOutcomeStatmentBeans.
     *
     * @param pageable the pagination information
     * @return the ResponseEntity with status 200 (OK) and the list of itfOutcomeStatmentBeans in body
     */
    @GetMapping("/itf-outcome-statment-beans")
    public ResponseEntity<List<ItfOutcomeStatmentBean>> getAllItfOutcomeStatmentBeans(Pageable pageable) {
        log.debug("REST request to get a page of ItfOutcomeStatmentBeans");
        Page<ItfOutcomeStatmentBean> page = itfOutcomeStatmentBeanRepository.findAll(pageable);
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/itf-outcome-statment-beans");
        return ResponseEntity.ok().headers(headers).body(page.getContent());
    }

    /**
     * GET  /itf-outcome-statment-beans/:id : get the "id" itfOutcomeStatmentBean.
     *
     * @param billNo the id of the itfOutcomeStatmentBean to retrieve
     * @return the ResponseEntity with status 200 (OK) and with body the itfOutcomeStatmentBean, or with status 404 (Not Found)
     */
    @GetMapping("/itf-outcome-statment-beans/{billNo}")
    public ResponseEntity<ItfOutcomeStatmentBean> getItfOutcomeStatmentBean(@PathVariable String billNo) {
        log.debug("REST request to get ItfOutcomeStatmentBean : {}", billNo);
        Optional<ItfOutcomeStatmentBean> itfOutcomeStatmentBean = itfOutcomeStatmentBeanRepository.findByBillNo(billNo);
        return ResponseUtil.wrapOrNotFound(itfOutcomeStatmentBean);
    }

    /**
     * DELETE  /itf-outcome-statment-beans/:id : delete the "id" itfOutcomeStatmentBean.
     *
     * @param billNo the id of the itfOutcomeStatmentBean to delete
     * @return the ResponseEntity with status 200 (OK)
     */
    @DeleteMapping("/itf-outcome-statment-beans/{billNo}")
    public ResponseEntity<Void> deleteItfOutcomeStatmentBean(@PathVariable String billNo) {
        log.debug("REST request to delete ItfOutcomeStatmentBean : {}", billNo);
        itfOutcomeStatmentBeanRepository.deleteByBillNo(billNo);
        itfOutcomeStatmentBeanSearchRepository.deleteByBillNo(billNo);
        return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, billNo.toString())).build();
    }

    /**
     * SEARCH  /_search/itf-outcome-statment-beans?query=:query : search for the itfOutcomeStatmentBean corresponding
     * to the query.
     *
     * @param query    the query of the itfOutcomeStatmentBean search
     * @param pageable the pagination information
     * @return the result of the search
     */
    @GetMapping("/_search/itf-outcome-statment-beans")
    public ResponseEntity<List<ItfOutcomeStatmentBean>> searchItfOutcomeStatmentBeans(@RequestParam String query, Pageable pageable) {
        log.debug("REST request to search for a page of ItfOutcomeStatmentBeans for query {}", query);
        Page<ItfOutcomeStatmentBean> page = itfOutcomeStatmentBeanSearchRepository.search(queryStringQuery(query), pageable);
        HttpHeaders headers = PaginationUtil.generateSearchPaginationHttpHeaders(query, page, "/api/_search/itf-outcome-statment-beans");
        return ResponseEntity.ok().headers(headers).body(page.getContent());
    }

    /**
     * @param
     * @return List
     * @throws Exception
     * @Title: 安装单
     * @Description: TODO 安装单生成对账单
     * @author LiJie
     * @date 20190318
     */
    @GetMapping("/saveAzStatement")
    public String saveAzStatement(@RequestParam String jhiAccount, @RequestParam int size) {
        log.debug("REST request to search for a page of saveAzStatement for query {}", jhiAccount);
        log.debug("安装单Start：生成对账单递归任务执行开始"+ LocalDate.now()+" "+ LocalTime.now().withNano(0).toString());
        String msg = "";
        azFinSettleCarsteamRepository.updateUpLockStatus(jhiAccount); //解锁,防止程序执行中出现问题导致未解锁
        int num = azFinSettleCarsteamRepository.findAllCount(jhiAccount);
        int ss = (num/size)+1;
        msg =  recursionMethod(jhiAccount,size,msg,ss,num);
        azFinSettleCarsteamRepository.updateUpLockStatus(jhiAccount); //将生成对账单失败的结算单解锁
        return msg;
    }

    public String recursionMethod(@RequestParam String jhiAccount, @RequestParam int size,String msg,int ss,int num) {
        try {
            if (num > 0) {
                int count = 0; //初始化线程数为0
                int hSize = size;
                if (size > 100) {  //如果处理的数据小于100条,默认使用一个线程
                    if (size % 100 > 0) {
                        count = (size/100)+1;
                    } else {
                        count = (size / 100);
                    }
                    if (count > 10) {
                        if(size%10 == 0){
                            count = 10;
                        }else {
                            count = 11;
                        }
                        size = size/count;
                    }
                } else {
                    count = 1;
                }

                // 创建一个线程池
                ExecutorService pool = Executors.newFixedThreadPool(count);
                // 创建多个有返回值的任务
                List<Future> listFuture = new ArrayList<Future>();
                for (int a = 0; a < count; a++) {
//                    Pageable pageable = PageRequest.of(initSize, size);
                    Thread.sleep(5000);
                    List<ItfOutcomeStatmentBean> list = itfOutcomeStatmentBeanRepository.findAllisNotCheckStatus(jhiAccount,size);
                    azFinSettleCarsteamRepository.updateLockStatus(jhiAccount,size); //加锁
                    Callable ol = new Ol(list, a + 1);
                    // 执行任务并获取Future对象
                    Future f = pool.submit(ol);
                    listFuture.add(f);
                }
                // 关闭线程池
                pool.shutdown();
                // 获取所有并发任务的运行结果
                for (Future f : listFuture) {
                    // 从Future对象上获取任务的返回值，并输出到控制台
                    msg += f.get().toString();
                }
                //递归处理数据
                for(int y = 0;y<ss;y++){
                    num = azFinSettleCarsteamRepository.findAllCount(jhiAccount);
                    if(num<hSize){
                        hSize = num;
                    }
                    recursionMethod(jhiAccount,hSize, msg,ss,num);
                }
                log.debug("安装单End：生成对账单递归任务执行结束"+ LocalDate.now()+" "+ LocalTime.now().withNano(0).toString());
            } else {
                msg += "没有查询到未生成对账单的结算单数据";
            }
        } catch (InterruptedException e) {
            msg += "获取线程返回值错误";
            e.printStackTrace();
        } catch (ExecutionException e) {
            msg += "安装结算单生成对账单异常";
            e.printStackTrace();
        }
        return msg;
    }
    @Transactional
    private String execute(List<ItfOutcomeStatmentBean> list, int n) {
        log.debug("第" + n + "线程的数据:" + list.size());
        StringBuffer errorSb = new StringBuffer("根据结算批次号查询不到结算明细{");
        StringBuffer sb1 = new StringBuffer();
        int succeed = 0; //成功条数
        int error = 0;   //错误条数
        int count = 0;
        String settBathId = "";
        try {
            for (int i = 0; i < list.size(); i++) {
                count++;
                ItfOutcomeStatmentBean obj = list.get(i);
                settBathId = obj.getBillNo();
                //根据结算单批次号查询结算明细
                List<ItfOutcomeStatmentDetailBean> billLiss = itfOutcomeStatmentDetailBeanRepository.findAllBySettleBatchId(obj.getStEntityCode(), obj.getBillNo());
                if (null != billLiss && billLiss.size() >= 0) {
                    succeed++;
//                    ls.add(obj);
                    obj.setId(null);
                    itfOutcomeStatmentBeanRepository.save(obj);
                    //批量保存对账单明细
//                    billData.addAll(billLiss);
                    for (ItfOutcomeStatmentDetailBean b : billLiss) {
                        b.setId(null);
                    }
                    itfOutcomeStatmentDetailBeanRepository.saveAll(billLiss);
                    //保存结算批次号,更新结算单
//                    settleBathIds.add(obj.getBillNo());
                    azFinSettleCarsteamRepository.batchUpdateBysettleBatchId(obj.getBillNo());
                } else {
                    error++;
                    errorSb.append(obj.getBillNo());
                }
            }
            errorSb.append("}");
            if (error == 0) {
                sb1.append("线程" + n + "执行总条" + list.size() + ",数操作成功," + succeed + "条");
            } else {
                sb1.append(errorSb);
            }
//            azFinSettleCarsteamRepository.batchUpdateBysettleBatchId(settleBathIds);
//            batchProcessingData(settleBathIds,ls,billData); //批量保存数据
            log.debug("｛结束｝第{" + n + "}线程执行成功:" + succeed + "条,失败:" + error + "条");
        } catch (Exception e) {
            sb1.append("｛异常｝第{" + n + "}线程第:" + count + "条,批次号{" + settBathId + "}");
            log.debug("｛异常｝第{" + n + "}线程第:" + count + "条,批次号{" + settBathId + "}");
            e.printStackTrace();
        }
        return sb1.toString();
    }

    // 线程的实现;
    class Ol implements Callable {
        int n = 0;
        List<ItfOutcomeStatmentBean> list;

        public Ol(List<ItfOutcomeStatmentBean> list, int n) {
            this.n = n;
            this.list = list;
        }

        @Override
        public Object call() throws Exception {
            return execute(list, n);
        }
    }

    private void batchProcessingData(List<String> settleBathIds, List<ItfOutcomeStatmentBean> ls, List<ItfOutcomeStatmentDetailBean> billData) {
        //批量更新结算单状态
        List<String> data1 = new ArrayList<>();
        List<ItfOutcomeStatmentBean> data2 = new ArrayList<>();
        List<ItfOutcomeStatmentDetailBean> data3 = new ArrayList<>();
        if (ls.size() > 0) {
            for (ItfOutcomeStatmentBean s : ls) {
                if (data2.size() == 50) {
                    itfOutcomeStatmentBeanRepository.saveAll(data2);
                    data2.clear();
                }
                data2.add(s);
            }
            //将剩下的数据也导入
            if (!data2.isEmpty()) {
                itfOutcomeStatmentBeanRepository.saveAll(data2);
            }
        }

        if (billData.size() > 0) {
            for (ItfOutcomeStatmentDetailBean s : billData) {
                if (data3.size() == 50) {
                    itfOutcomeStatmentDetailBeanRepository.saveAll(data3);
                    data3.clear();
                }
                data3.add(s);
            }
            //将剩下的数据也导入
            if (!data3.isEmpty()) {
                itfOutcomeStatmentDetailBeanRepository.saveAll(data3);
            }
        }

        if (settleBathIds.size() > 0) {
            for (String s : settleBathIds) {
                if (data1.size() == 50) {
                    azFinSettleCarsteamRepository.batchUpdateBysettleBatchId(data1);
                    data1.clear();
                }
                data1.add(s);
            }
            //将剩下的数据也导入
            if (!data1.isEmpty()) {
                azFinSettleCarsteamRepository.batchUpdateBysettleBatchId(data1);
            }
        }
    }
}
